package com.hengshan.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hengshan.common.enums.ReturnCode;
import com.hengshan.domain.entity.Role;
import com.hengshan.domain.entity.RoleMenu;
import com.hengshan.domain.entity.User;
import com.hengshan.domain.entity.UserRole;
import com.hengshan.domain.vo.PageVo;
import com.hengshan.exception.SystemException;
import com.hengshan.mapper.RoleMapper;
import com.hengshan.service.RoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色表(Role)表服务实现类
 *
 * @author muxijun
 * @since 2023-12-22 15:43:24
 */
@Service("roleService")
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    public static final int ROLE_STATUS_ON = 1; // 角色状态启用

    private final RoleMapper roleMapper;
    private final RoleMenuServiceImpl roleMenuService;
    private final UserRoleServiceImpl userRoleService;

    @Transactional
    public boolean deleteByIds(List<Integer> ids) {
        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(RoleMenu::getRoleId, ids);
        return roleMenuService.remove(queryWrapper) && removeBatchByIds(ids);
    }

    @Transactional
    public boolean deleteById(Integer id) {
        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleMenu::getRoleId, id);
        return roleMenuService.remove(queryWrapper) && removeById(id);
    }

    public PageVo<Role> getList(int pageNum, int pageSize, String name, String roleKey) {
        LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(name), Role::getName, name)
                .like(StringUtils.hasText(roleKey), Role::getRoleKey, roleKey);
        Page<Role> page = new Page<>(pageNum, pageSize);
        page(page, wrapper);
        return new PageVo<>(page.getRecords(), page.getTotal());
    }

    public Role getOneById(Integer id) {
        return getById(id);
    }

    @Transactional
    public Role add(Role role) {
        checkUnique(role);
        save(role);
        //添加角色权限关联信息
        List<RoleMenu> roleMenus = role.getMenuIds().stream()
                .map(menuId -> new RoleMenu(role.getId(), menuId)).collect(Collectors.toList());
        roleMenuService.saveBatch(roleMenus);
        return getById(role.getId());
    }

    @Transactional
    public boolean update(Role role) {
        checkRoleAllowed(role);
        checkUnique(role);
        boolean rs = updateById(role);
        if (!CollectionUtils.isEmpty(role.getMenuIds())) {
            List<RoleMenu> roleMenus = role.getMenuIds().stream()
                    .map(menuId -> new RoleMenu(role.getId(), menuId)).collect(Collectors.toList());
            LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
            roleMenuService.remove(queryWrapper.eq(RoleMenu::getRoleId, role.getId()));
            rs = roleMenuService.saveBatch(roleMenus);
        }
        return rs;
    }

    @Override
    public List<Role> selectRolesByUserId(Long userId) {
        return roleMapper.selectRolesByUserId(userId, ROLE_STATUS_ON);
    }

    public List<Role> selectRolesByUser(User user) {
        return roleMapper.selectRolesByUserId(user.getId(), ROLE_STATUS_ON);
    }

    /**
     * 获取角色数据权限
     *
     * @param user 用户信息
     * @return 角色权限信息
     */
    public List<String> getRolePermission(User user) {
        List<String> roleKeys = new ArrayList<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            roleKeys.add("admin");
        } else {
            List<Role> roles = roleMapper.selectRolesByUserId(user.getId(), ROLE_STATUS_ON);
            roleKeys = roles.stream().map(Role::getRoleKey).collect(Collectors.toList());
        }
        return roleKeys;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    public void checkRoleAllowed(Role role) {
        if (role.isAdmin()) {
            throw new SystemException(ReturnCode.ACCESS_DENIED.getCode(), "不允许操作超级管理员角色");
        }
    }

    public void checkUnique(Role role) {
        //校验角色名，角色标识符是否存在
        if (StringUtils.hasText(role.getName())) {
            boolean checkName = roleMapper.exists(new LambdaQueryWrapper<Role>()
                    .eq(Role::getName, role.getName())
                    .ne(role.getId() != null, Role::getId, role.getId()));
            if (checkName) {
                throw new SystemException(ReturnCode.ROLE_EXIST);
            }
        }
        if (StringUtils.hasText(role.getRoleKey())) {
            boolean checkRoleKey = roleMapper.exists(new LambdaQueryWrapper<Role>()
                    .eq(Role::getRoleKey, role.getRoleKey())
                    .ne(role.getId() != null, Role::getId, role.getId()));
            if (checkRoleKey) {
                throw new SystemException(ReturnCode.ROLE_KEY_EXIST);
            }
        }
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    public int updateRoleStatus(Role role) {
        return roleMapper.updateById(role);
    }

    public boolean deleteAuthUser(Integer roleId, Long userId) {
        return userRoleService.remove(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getUserId, userId)
                .eq(UserRole::getRoleId, roleId));
    }

    public boolean deleteAuthUsers(Integer roleId, String[] userIds) {
        return userRoleService.remove(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getRoleId, roleId)
                .in(UserRole::getUserId, userIds));
    }

    public boolean insertAuthUsers(Integer roleId, String[] userIds) {
        List<UserRole> userRoles = Arrays.stream(userIds).map(userId -> new UserRole(Long.valueOf(userId), roleId)).collect(Collectors.toList());
        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        return userRoleService.saveBatch(userRoles);
    }
}
